Ext.define('Zm.view.x3d.X3dView', {
    extend: 'Ext.Component',
    alias: 'widget.x3dview',
    requires:[
        'Ext.util.DelayedTask',
        'Zm.i18n.Lang'
    ],
    initComponent: function() {
        var me = this,
            lang = Zm.i18n.Lang;
        me.tag = 'dev_';
        me.x3dElement = null;
        Ext.apply(me, {
            resizable:true,
            loader:{
                url:g_app+'/X3d/main',
                autoLoad:true,
                listeners:{
                    load:{
                        fn:me.onLoad,
                        scope:me
                    }
                }
            }
        });

        me.addEvents('devmouseover','devmouseout','devmousedown','devmouseup','devclick','poschange');

        me.saveTask = new Ext.util.DelayedTask(function(){
            me.saveViewpoint();
        });
        
        me.originalVP = null;
        me.objLines = null;
        me.objPosTran = null;
        me.isMovePos = false;
        me.transOffset = null;
        me.buttonState = 0;
        me.w = 0;
        me.h = 0;
        me.uPlane = null;
        me.vPlane = null;
        me.pPlane = null;
        me.isect = null;
        me.firstRay = null;
        me.lastX = 0;
        me.lastY = 0;
        me.devCol = new Ext.util.MixedCollection();
        
        me.objTourVp = null;
        me.objTourTimer = null;
        me.objTourPos =null;
        me.objTourOri = null;
        
        me.callParent(arguments);
    },
    onLoad:function(){
        var me = this,viewpoint,
            devs = me.getEl().query('*');
        me.devCol.clear();
        if(devs){
            devs.forEach(me.addForEvent,me);
        }
        x3dom.reload();
        me.x3dElement = me.findElement('#x3droot');
        me.objLines = me.findElement('#line_all');
        me.objPosTran = me.findElement('#pos_tran');
        me.objRoot = me.findElement('#RootNode');
        
        me.objTourVp = me.findElement('#tour_vp');
        me.objTourTimer = me.findElement('#tour_timer');
        me.objTourPos = me.findElement('#tour_pos_inter');
        me.objTourOri = me.findElement('#tour_orie_inter');
        
        me.objPosTran.addEventListener('mousedown', Ext.bind(me.enterMove,me), false);
        me.x3dElement.addEventListener('mousemove', Ext.bind(me.onPMove,me), true);
        me.objRoot.addEventListener('mouseup', Ext.bind(me.onPStop,me), false);
        
        me.isMovePos = false;
        
        viewpoint = document.getElementById('aView');
        
        if(viewpoint) viewpoint.addEventListener('viewpointChanged', Ext.bind(me.onVpChange,me,viewpoint,true), false);
    },
    findElement:function(path){
        var res = this.getEl().query(path);
        if(res.length>0){
            return res[0];
        }
        return null;
    },
    addForEvent:function(element,index,array){
        var me = this,devid,sPath,
            len = me.tag.length;
        if(element.id.substr(0,len)==me.tag){
            devid = element.id.substr(len);
            me.addElEvent(element,devid);
            me.devCol.add(devid,element.getAttribute('spath'));
        }
    },
    addElEvent:function(element,devid){
        var me = this;
        element.onmouseover = Ext.bind(me.onMouseOver,me,[devid,element],true);
        element.onmouseup = Ext.bind(me.onMouseUp,me,[devid,element],true);
        element.onmousedown = Ext.bind(me.onMouseDown,me,[devid,element],true);
        element.onmouseout = Ext.bind(me.onMouseOut,me,[devid,element],true);
        element.onclick = Ext.bind(me.onDevClick,me,[devid,element],true);        
    },
    onMouseDown:function(event,devid,element){
        var me = this;
        event.cancelBubble = true;
        me.fireEvent('devmousedown',me,devid,element,event);
    },
    onMouseOver:function(event,devid,element){
        var me = this,pos;
        event.cancelBubble = true;
        me.fireEvent('devmouseover',me,devid,element,event);
    },
    onMouseOut:function(event,devid,element){
        var me = this;
        event.cancelBubble = true;
        me.fireEvent('devmouseout',me,devid,element,event);
    },
    onMouseUp:function(event,devid,element){
        var me = this;
        event.cancelBubble = false;
        me.fireEvent('devmouseup',me,devid,element,event);
    },
    onDevClick:function(event,devid,element){
        var me = this;
        event.cancelBubble = true;
        me.fireEvent('devclick',me,devid,element,event);
    },
    setTrans:function(transNode,data){
        if(data.translation) transNode.setAttribute('translation',data.translation);
        if(data.scale) transNode.setAttribute('scale',data.scale);
        if(data.center) transNode.setAttribute('center',data.center);
        if(data.rotation) transNode.setAttribute('rotation',data.rotation);        
    },
    transDev:function(devid,data){
        var me = this,
            transNode = me.findElement('#trans_'+devid);
        if(transNode){
            me.setTrans(transNode,data);
        }
    },
    
    addDevToDom:function(parentNode,data){
        var me = this,i,spath,
            devid = data.devid,
            transNode = document.createElement('Transform'),
            node = document.createElement('Group'),
            model;
        transNode.setAttribute('id','trans_'+devid);
        node.setAttribute('id','dev_'+devid);
        me.addElEvent(node,devid);
        transNode.appendChild(node);
        if(data.transform) me.setTrans(transNode,data.transform);
        spath = parentNode.getAttribute('spath')+'/'+devid;
        node.setAttribute('spath',spath);
        if(data.modelurl){
            model = document.createElement('Inline');
            node.appendChild(model);
            model.setAttribute('url',data.modelurl);
        }
        if(data.children){
            for(i=0;i<data.children.length;i++){
                me.addDevToDom(node,data.children[i]);
            }
        }
        parentNode.appendChild(transNode);  
        me.devCol.add(devid,spath);
    },
    addDev:function(data){
        var me = this,
            parentNode = me.findElement('#dev_'+data.parentid);
        
        me.addDevToDom(parentNode,data);
    },
    delDev:function(devid){
        var me = this,
            node = me.findElement('#trans_'+devid);
        if(node){
            node.parentNode.removeChild(node);
            me.devCol.removeAtKey(devid);
        }
    },
    onVpChange:function(evt){
        var me = this
            pos = evt.position,
            rot = evt.orientation;
        me.originalVP = {position:pos.x.toFixed(4)+' '+pos.y.toFixed(4)+' '+pos.z.toFixed(4),orientation:rot[0].x.toFixed(4)+' '+rot[0].y.toFixed(4)+' '+rot[0].z.toFixed(4)+' '+rot[1].toFixed(4)};
        me.saveTask.delay(5000);
    },
    saveViewpoint:function(){
        var me = this;
        Ext.Ajax.request({
            url: g_app + '/X3d/saveVP',
            params: me.originalVP,
            scope: me,
            success:function(response,options){ 
            }
         });            
    },
    goDev:function(devid){
        var me = this,
            devEl = me.findElement('#dev_'+devid);
        me.x3dElement.runtime.gotoObject(devEl);
    },
    getXyz:function(devid){
        var me = this,trans,
            devEl = me.findElement('#dev_'+devid);
        if(devEl){
            trans = devEl._x3domNode.getCurrentTransform();
            return ''+ trans._03 + ' ' + trans._13 + ' ' + trans._23;
        }else{
            return '';
        }
    },
    showLines:function(bShow){
        var me = this;
        if(me.objLines){
            if(bShow){
                me.objLines.setAttribute('render',true);
            }else{
                me.objLines.setAttribute('render',false);
            }
        }
    },
    refLines:function(){
        var me = this,i,j,node,linedata,
            lineid='';
        if(arguments.length>0){
            lineid = arguments[0];
        }
        Ext.Ajax.request({
            url: g_app + '/Lines/getLines',
            scope: me,
            params:{lineid:lineid},
            success:function(response,options){ 
                var obj = Ext.decode(response.responseText,true);
                     if(obj==null) return;
                     if(obj.success){
                         if(lineid==''){
                             for(i=0;i<me.objLines.childNodes.length;i++){
                                 me.objLines.removeChild(me.objLines.childNodes[i]);
                             }
                         }else{
                             me.delLine(lineid);                             
                         }
                         //添加连接线
                         for(i=0;i<obj.data.length;i++){
                             linedata = obj.data[i];
                             me.addLine(linedata);
                         }
                     }
            },
            failure:Zm.Common.onAFail
         });    
    },
    delLine:function(lineid){
        var me = this,
            node = me.findElement('#ln_'+lineid);
        if(node){
            node.parentNode.removeChild(node);
        }
    },
    addLine:function(linedata){
        var me = this,shape,appearance,material,lp,idl,sc,sp,cp;
        if(linedata.devs.length<2) return;
        shape = document.createElement('Shape');
        shape.setAttribute('id','ln_'+linedata.lineid);
        appearance = document.createElement('Appearance');
        material = document.createElement('Material');
        material.setAttribute('USE','lnt_' + linedata.linetype);
        appearance.appendChild(material);
        lp = document.createElement('LineProperties');
        lp.setAttribute('USE','lnp_' + linedata.linetype);
        appearance.appendChild(lp);
        idl = document.createElement('IndexedLineSet');
        sc = '0';
        sp = me.getXyz(linedata.devs[0].devid);
        for(j=0;j<linedata.xyz.length;j++){
        sc += ' ' + (j+1);
        sp += ' ' + linedata.xyz[j].xyz;
        }
        sc += ' ' + (j+1);
        sp += ' ' + me.getXyz(linedata.devs[1].devid);
        idl.setAttribute('coordIndex',sc);
        cp = document.createElement('Coordinate');
        cp.setAttribute('point',sp);
        idl.appendChild(cp);
        shape.appendChild(idl);

        shape.appendChild(appearance);

        me.objLines.appendChild(shape);        
    },
    enterMove:function(event){
        var me = this,
            runtime = me.x3dElement.runtime,
            trans;
        if(!me.isMovePos){
            me.lastX = event.layerX;
            me.lastY = event.layerY;
            me.isMovePos = true;
            runtime.noNav();
            me.isect = new x3dom.fields.SFVec3f(event.worldX, event.worldY, event.worldZ);
            me.calcViewPlane(me.isect);
            
            me.firstRay = runtime.getViewingRay(event.layerX, event.layerY);
            me.buttonState = event.button;
            trans = me.objPosTran.getAttribute("translation");
            if(trans)
                me.transOffset = x3dom.fields.SFVec3f.parse(trans);
            else
                me.transOffset = new x3dom.fields.SFVec3f(0, 0, 0);
        }
    },
    onPMove:function(event){
        var me = this,pos,ray,track=null,xyz,
            runtime = me.x3dElement.runtime;
        if(me.isMovePos){
            pos = runtime.mousePosition(event);
            ray = runtime.getViewingRay(pos[0], pos[1]);
            
            track = null;
            
            if (me.buttonState == 2)   // right mouse button
                track = me.translateZ(me.firstRay, pos[1]);
            else
                track = me.translateXY(ray);
            
            if (track){
                xyz = track.x.toFixed(4) + " " + track.y.toFixed(4) + " " + track.z.toFixed(4);
                me.objPosTran.setAttribute("translation", xyz);
                me.fireEvent('poschange',me,xyz);
            }
            me.lastX = pos[0];
            me.lastY = pos[1];
        }    
    },
    onPStop:function(event){
        var me = this,
            runtime = me.x3dElement.runtime;
        if(me.isMovePos){
            me.lastX = event.layerX;
            me.lastY = event.layerY;
            me.isect = null;
            me.isMovePos = false;
            runtime.examine();
        }
    },
    calcViewPlane:function(origin){
        var me = this,r,s,t,
            runtime = me.x3dElement.runtime,
            ray = null;
        
        // init width and height
        me.w = runtime.getWidth();
        me.h = runtime.getHeight();
        
        ray = runtime.getViewingRay(0, me.h-1);
        r = ray.pos.add(ray.dir);   //bottom left of viewarea

        ray = runtime.getViewingRay(me.w-1, me.h-1);
        s = ray.pos.add(ray.dir);   //bottom right of viewarea

        ray = runtime.getViewingRay(0, 0);
        t = ray.pos.add(ray.dir);   //top left of viewarea
        
        me.uPlane = s.subtract(r).normalize();
        me.vPlane = t.subtract(r).normalize();
        
        if (arguments.length === 0)
            me.pPlane = r;
        else
            me.pPlane = x3dom.fields.SFVec3f.copy(origin);
    },
    
    det:function(mat){
        return     mat[0][0]*mat[1][1]*mat[2][2] + mat[0][1]*mat[1][2]*mat[2][0] +
                mat[0][2]*mat[2][1]*mat[1][0] - mat[2][0]*mat[1][1]*mat[0][2] -
                mat[0][0]*mat[2][1]*mat[1][2] - mat[1][0]*mat[0][1]*mat[2][2] ;
    },
    
    // translation along plane parallel to viewing plane E:x=p+t*u+s*v
    translateXY:function(l){
        var me = this,track = null,i,s,t,
            z = [], n = [];

        for (i=0; i<3; i++) {
            z[i] = [];
            n[i] = [];
            
            z[i][0] = me.uPlane.at(i);
            n[i][0] = z[i][0];
            
            z[i][1] = me.vPlane.at(i);
            n[i][1] = z[i][1]
            
            z[i][2] = (l.pos.subtract(me.pPlane)).at(i);
            n[i][2] = -l.dir.at(i);
        }
        
        // get intersection line-plane with cramer's rule
        s = me.det(n);
        
        if (s !== 0) {
            t = me.det(z) / s;
            track = l.pos.addScaled(l.dir, t);
        }
        
        if (track) {
            if (me.isect) {
                // calc offset from first click position
                track = track.subtract(me.isect);
            }
            track = track.add(me.transOffset);
        }
        
        return track;
    },
    
    // translation along picking ray to zoom object in/out
    translateZ:function(l, currY){
        var me = this,
            vol = me.x3dElement.runtime.getSceneBBox(),
            sign = (currY < me.lastY) ? 1 : -1,
            fact = sign * (vol.max.subtract(vol.min)).length() / 50;
        
        me.transOffset.setValues(me.transOffset.addScaled(l.dir, fact));
        
        return me.transOffset;
    },
    showOnly:function(){
        var me = this,i,devid,spath,devArr,j,n,devids = new Array(),el;
        for(i=0;i<arguments.length;i++){
            devid = arguments[i];
            if(Ext.isArray(devid)){
                for(j=0;j<devid.length;j++){
                    spath = me.devCol.get(devid[j]);
                    devArr = spath.split('/');
                    devids = devids.concat(devArr);                                  
                }
            }else{
                spath = me.devCol.get(devid);
                devArr = spath.split('/');
                devids = devids.concat(devArr);              
            }
        }
        me.devCol.eachKey(function(key,item,index,len){
            n = devids.indexOf(key);
            el = me.findElement('#trans_'+key);
            if(el){
                if(n==-1){
                    el.setAttribute('render',false);
                }else{
                    el.setAttribute('render',true);
                }
            }
        });
    },
    showAll:function(){
        var me = this,el;
        me.devCol.eachKey(function(key,item,index,len){
            el = me.findElement('#trans_'+key);
            if(el) el.setAttribute('render',true);
        });
    }
        
});
